import tkinter as tk
import ttkbootstrap as ttk
from tkinter import filedialog, messagebox
import os
from pathlib import Path


class BatchRenameApp:
    def __init__(self, root):
        self.root = root
        self.root.title("批量文件重命名工具")

        # 绑定窗口大小变化事件
        self.root.bind("<Configure>", self.on_window_resize)

        # 创建主题并设置颜色
        self.style = ttk.Style(theme="flatly")

        # 修改主题颜色
        self.style.colors.primary = "#9683EC"
        self.style.colors.secondary = "#9683EC"
        self.style.colors.success = "#9683EC"
        self.style.colors.info = "#9683EC"
        self.style.colors.warning = "#9683EC"
        self.style.colors.danger = "#9683EC"

        # 设置全局颜色
        self.style.configure(".",
                             background="white",
                             foreground="black")

        # 创建主框架
        self.main_frame = ttk.Frame(self.root, padding="20")
        self.main_frame.pack(fill=tk.BOTH, expand=True)

        # 存储选择的文件
        self.selected_files = []

        # 选择文件按钮和文件列表框架
        self.source_frame = ttk.LabelFrame(self.main_frame, text="加载文件路径", padding="10")
        self.source_frame.pack(fill=tk.X, pady=(0, 10))

        self.select_btn = ttk.Button(
            self.source_frame,
            text="浏览",
            command=self.select_files,
            bootstyle="danger"
        )
        self.select_btn.pack(side=tk.RIGHT)

        self.file_listbox = ttk.Treeview(self.source_frame, columns=("path",), show="", height=4)
        self.file_listbox.pack(fill=tk.X, expand=True, padx=(0, 10))

        # 重命名选项框架
        rename_frame = ttk.LabelFrame(self.main_frame, text="重命名选项", padding="10")
        rename_frame.pack(fill=tk.X, pady=(0, 10))

        # 添加保留原文件名选项
        self.use_original_var = tk.BooleanVar(value=False)
        ttk.Checkbutton(rename_frame, text="保留原文件名（只修改扩展名）",
                        variable=self.use_original_var,
                        command=self.toggle_rename_options,
                        bootstyle="danger-round-toggle").pack(anchor=tk.W, pady=(0, 5))

        # 创建包含前缀、后缀和编号设置的子框架
        self.rename_options_frame = ttk.Frame(rename_frame)
        self.rename_options_frame.pack(fill=tk.X)

        # 前缀和后缀输入框架
        prefix_suffix_frame = ttk.Frame(self.rename_options_frame)
        prefix_suffix_frame.pack(fill=tk.X, pady=(0, 5))

        ttk.Label(prefix_suffix_frame, text="前缀:").pack(side=tk.LEFT)
        self.prefix_var = tk.StringVar()
        self.prefix_entry = ttk.Entry(prefix_suffix_frame, textvariable=self.prefix_var, width=20)
        self.prefix_entry.pack(side=tk.LEFT, padx=(5, 20))

        ttk.Label(prefix_suffix_frame, text="后缀:").pack(side=tk.LEFT)
        self.suffix_var = tk.StringVar()
        self.suffix_entry = ttk.Entry(prefix_suffix_frame, textvariable=self.suffix_var, width=20)
        self.suffix_entry.pack(side=tk.LEFT, padx=5)

        # 编号设置框架
        number_frame = ttk.Frame(self.rename_options_frame)
        number_frame.pack(fill=tk.X, pady=5)

        ttk.Label(number_frame, text="起始编号:").pack(side=tk.LEFT)
        self.start_num_var = tk.StringVar(value="1")
        self.start_num_entry = ttk.Entry(number_frame, textvariable=self.start_num_var, width=10)
        self.start_num_entry.pack(side=tk.LEFT, padx=(5, 20))

        ttk.Label(number_frame, text="编号位数:").pack(side=tk.LEFT)
        self.num_digits_var = tk.StringVar(value="2")
        self.num_digits_entry = ttk.Entry(number_frame, textvariable=self.num_digits_var, width=10)
        self.num_digits_entry.pack(side=tk.LEFT, padx=5)

        # 扩展名修改框架
        ext_frame = ttk.LabelFrame(self.main_frame, text="扩展名修改", padding="10")
        ext_frame.pack(fill=tk.X, pady=(0, 10))

        self.ext_var = tk.StringVar(value="keep")
        ttk.Radiobutton(ext_frame, text="保持原扩展名",
                        variable=self.ext_var, value="keep",
                        bootstyle="danger-round-toggle").pack(side=tk.LEFT, padx=(0, 20))
        ttk.Radiobutton(ext_frame, text="修改扩展名",
                        variable=self.ext_var, value="change",
                        bootstyle="danger-round-toggle").pack(side=tk.LEFT, padx=(0, 20))

        ttk.Label(ext_frame, text="新扩展名:").pack(side=tk.LEFT)
        self.new_ext_var = tk.StringVar()
        self.new_ext_entry = ttk.Entry(ext_frame, textvariable=self.new_ext_var, width=10)
        self.new_ext_entry.pack(side=tk.LEFT, padx=5)
        ttk.Label(ext_frame, text="(例如: .txt)").pack(side=tk.LEFT, padx=5)

        # 预览区域
        preview_frame = ttk.LabelFrame(self.main_frame, text="预览", padding="10")
        preview_frame.pack(fill=tk.X, pady=(0, 10))

        self.preview_listbox = ttk.Treeview(preview_frame, columns=("preview",), show="", height=6)
        self.preview_listbox.pack(fill=tk.X, expand=True)

        # 重命名按钮
        self.rename_btn = ttk.Button(
            self.main_frame,
            text="开始重命名",
            command=self.rename_files,
            bootstyle="danger"
        )
        self.rename_btn.pack(pady=(0, 10))

        # 绑定输入变化事件
        self.prefix_var.trace('w', self.update_preview)
        self.suffix_var.trace('w', self.update_preview)
        self.start_num_var.trace('w', self.update_preview)
        self.num_digits_var.trace('w', self.update_preview)
        self.ext_var.trace('w', self.update_preview)
        self.new_ext_var.trace('w', self.update_preview)

    def select_files(self):
        files = filedialog.askopenfilenames(title="选择要重命名的文件")
        self.selected_files = list(files)
        self.file_listbox.delete(*self.file_listbox.get_children())
        for file in self.selected_files:
            self.file_listbox.insert("", "end", values=(file,))
        self.update_preview()

    def toggle_rename_options(self):
        """切换重命名选项区域的可用状态"""
        state = "disabled" if self.use_original_var.get() else "normal"

        # 设置所有子控件状态
        for widget in self.rename_options_frame.winfo_children():
            for subwidget in widget.winfo_children():
                if isinstance(subwidget, ttk.Entry):
                    subwidget.configure(state=state)

        # 更新预览
        self.update_preview()

    def get_new_extension(self, old_extension):
        """根据用户选择返回新的扩展名"""
        if self.ext_var.get() == "keep":
            return old_extension
        new_ext = self.new_ext_var.get().strip()
        # 确保新扩展名以点号开头
        if new_ext and not new_ext.startswith('.'):
            new_ext = '.' + new_ext
        return new_ext

    def update_preview(self, *args):
        self.preview_listbox.delete(*self.preview_listbox.get_children())
        if not self.selected_files:
            return

        try:
            start_num = int(self.start_num_var.get())
            num_digits = int(self.num_digits_var.get())
        except ValueError:
            return

        for i, file in enumerate(self.selected_files):
            old_name = os.path.basename(file)
            name_without_ext, old_extension = os.path.splitext(old_name)
            # 获取新的扩展名
            new_extension = self.get_new_extension(old_extension)

            # 根据是否保留原文件名决定新文件名格式
            if self.use_original_var.get():
                # 只修改扩展名，保留原文件名
                new_name = f"{name_without_ext}{new_extension}"
            else:
                # 使用前缀+编号+后缀+扩展名格式
                new_name = (f"{self.prefix_var.get()}"
                            f"{str(start_num + i).zfill(num_digits)}"
                            f"{self.suffix_var.get()}{new_extension}")

            self.preview_listbox.insert("", "end", values=(f"{old_name} -> {new_name}",))

    def rename_files(self):
        if not self.selected_files:
            messagebox.showwarning("警告", "请先选择文件！")
            return

        try:
            start_num = int(self.start_num_var.get())
            num_digits = int(self.num_digits_var.get())
        except ValueError:
            messagebox.showerror("错误", "起始编号和编号位数必须为数字！")
            return

        # 检查新扩展名格式
        if self.ext_var.get() == "change":
            new_ext = self.new_ext_var.get().strip()
            if not new_ext:
                messagebox.showerror("错误", "请输入新的扩展名！")
                return

        try:
            # 第一步：先将所有文件重命名为临时名称
            temp_names = {}
            for i, file in enumerate(self.selected_files):
                old_path = file
                directory = os.path.dirname(file)
                old_name = os.path.basename(file)
                temp_name = f"__TEMP__{i}__{old_name}"
                temp_path = os.path.join(directory, temp_name)
                os.rename(old_path, temp_path)
                temp_names[temp_name] = (i, old_name, directory)

            # 第二步：将临时名称重命名为目标名称
            renamed_count = 0
            for temp_name, (i, old_name, directory) in temp_names.items():
                name_without_ext, old_extension = os.path.splitext(old_name)
                new_extension = self.get_new_extension(old_extension)

                # 根据是否保留原文件名决定新文件名格式
                if self.use_original_var.get():
                    # 只修改扩展名，保留原文件名
                    new_name = f"{name_without_ext}{new_extension}"
                else:
                    # 使用前缀+编号+后缀+扩展名格式
                    new_name = (f"{self.prefix_var.get()}"
                                f"{str(start_num + i).zfill(num_digits)}"
                                f"{self.suffix_var.get()}{new_extension}")

                temp_path = os.path.join(directory, temp_name)
                new_path = os.path.join(directory, new_name)
                os.rename(temp_path, new_path)
                renamed_count += 1

            messagebox.showinfo("成功", "文件重命名完成！")
            self.file_listbox.delete(*self.file_listbox.get_children())
            self.preview_listbox.delete(*self.preview_listbox.get_children())
            self.selected_files = []

        except Exception as e:
            messagebox.showerror("错误", f"重命名时发生错误：{str(e)}")

    def on_window_resize(self, event):
        # 获取窗口的实际大小
        window_width = self.root.winfo_width()
        window_height = self.root.winfo_height()

        # 根据窗口大小调整组件
        # 这里可以添加更多自适应逻辑如果需要

        # 更新滚动区域
        self.main_frame.update_idletasks()


def main():
    # 启用DPI感知
    try:
        from ctypes import windll
        windll.shcore.SetProcessDpiAwareness(1)
    except:
        pass  # 如果失败，继续执行

    root = ttk.Window()

    # 设置窗口初始大小
    root.geometry("600x700")

    # 设置最小窗口大小
    root.minsize(500, 550)

    app = BatchRenameApp(root)

    # 更新窗口以确保所有组件都已正确布局
    root.update()

    # 获取内容的实际大小
    required_width = app.main_frame.winfo_reqwidth()
    required_height = app.main_frame.winfo_reqheight()

    # 调整窗口大小以适应内容
    root.geometry(f"{required_width}x{required_height}")

    # 允许窗口调整大小
    root.resizable(True, True)

    root.mainloop()


if __name__ == "__main__":
    main()
